/**
 * @constructor
 * @param {MowerFileInputReader} mowerFileInputReader
 * @param {Function} mowerDriveOutputCallback
 * @returns {MowerDriver}
 */
function MowerDriver(mowerFileInputReader, mowerDriveOutputCallback) {
	this.mowerInputReader = mowerFileInputReader;
	this.mowerDriveOutputCallback = mowerDriveOutputCallback;	
	this.drivingContext;	
	this.isMowersEnd;
	this.isCurrentMowerCommandsEnd;
	this.currentMower = null;
};

/**
 * @public 
 */
MowerDriver.prototype.driveMowers = function() {
	this.initMowerFileInputCallbacks();
	this.initDrivingContext();
	this.commandMowers();
};

/**
 * @private
 */
MowerDriver.prototype.initMowerFileInputCallbacks = function() {
	var self = this;
	this.mowerInputReader.setCurrentMowerCommandsEndCallback(function() {
		self.isCurrentMowerCommandsEnd = true;
	});
	this.mowerInputReader.setMowersEndedCallback(function() {
		self.isMowersEnd = true;
	});
};

/**
 * @private
 */
MowerDriver.prototype.initDrivingContext = function() {
	var lawnUpperRightCorner = this.mowerInputReader.getLawnCorner();
	if(lawnUpperRightCorner.x <= 0 || lawnUpperRightCorner.y <= 0) {
		throw new InvalidLawnDimensionsException("Lawn dimensions shouldn't be negative!");
	}
	this.drivingContext = new MowersDrivingContext(lawnUpperRightCorner.x + 1 , lawnUpperRightCorner.y + 1);
};

/**
 * @private
 */
MowerDriver.prototype.commandMowers = function() {
	this.processNextMower();			
	while(!this.isMowersEnd) {
		this.processNextMower();
	}
};

/**
 * @private
 */
MowerDriver.prototype.processNextMower = function() {
	this.isCurrentMowerCommandsEnd = false;
	try {
		var mowerStartVector = this.mowerInputReader.nextStartVector();
		if(this.isMowersEnd) {
			return;
		}
		this.placeMower(mowerStartVector);
	} catch (e) {
		LOGGER.log(e);
		return;
	}
	
	this.processNextCommand();		
	while(!this.isCurrentMowerCommandsEnd) {
		this.processNextCommand();		
	}
	this.processDriveResults();
};

/**
 * @private
 */
MowerDriver.prototype.processNextCommand = function() {
	try {
		var command = this.mowerInputReader.nextCommand();
		if(this.isCurrentMowerCommandsEnd) {
			return;
		}
		this.commandMower(command);
	} catch (e) {
		LOGGER.log(e);
	}
};

/**
 * @private
 * @param {MowerVector} mowerStartVector
 */
MowerDriver.prototype.placeMower = function(mowerStartVector) {
	var mowerIndex = this.currentMower == null ? 0 : this.currentMower.getMowerIndex() + 1;
	this.currentMower = new Mower(mowerIndex, this.drivingContext);
	this.currentMower.placeMower(mowerStartVector);
};

/**
 * @private
 * @param command
 */
MowerDriver.prototype.commandMower = function(command) {
	this.currentMower.execute(command);
};

/**
 * @private
 */
MowerDriver.prototype.processDriveResults = function() {
	var driveResult = this.generateDriveResult();
	this.mowerDriveOutputCallback(driveResult);
};

/**
 * @private
 * @returns {MowerDriveResult}
 */
MowerDriver.prototype.generateDriveResult = function() {
	return new MowerDriveResult(this.currentMower.mowerIndex, this.currentMower.currentVector);
};